package ar.edu.utn.frba.tacs.warnes.pedido;

import java.util.List;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Transient;

import ar.edu.utn.frba.tacs.warnes.BaseEntity;
import ar.edu.utn.frba.tacs.warnes.BaseEntityImpl;
import ar.edu.utn.frba.tacs.warnes.aop.Utils;
import ar.edu.utn.frba.tacs.warnes.dao.BaseDaoImpl;
import ar.edu.utn.frba.tacs.warnes.dao.PedidoDao;
import ar.edu.utn.frba.tacs.warnes.excepciones.SoyUnPedidoCanceladoException;
import ar.edu.utn.frba.tacs.warnes.pieza.Pieza;

@Entity
public class Pedido extends BaseEntityImpl {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO, generator = "PiezaSeq")
	@SequenceGenerator(name = "PiezaSeq", sequenceName = "PiezaSeq")
	private Long id;
	
	//TODO como mapeo un strategy en la base de datos??? :S
	@Transient
	private PedidoStrategy pedidoStrategy;

	/**
	 * Crea un pedido en estado reservado con un conjunto de piezas dadas
	 * @param piezas
	 */
	public Pedido(List<Pieza> piezas) {
		this.reservar(piezas);
	}

	public Long getId() {
		return this.id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	/**
	 * El Strategy se encarga de devolverme las piezas que posee el pedido.
	 * @return List<Pieza>
	 * @throws SoyUnPedidoCanceladoException
	 */
	public List<Pieza> getPiezas() {
		return this.getPedidoStrategy().getPiezas();
	}

	/**
	 * Delego en el Strategy la responsabilidad de agregar piezas segun sea posible.
	 * @param pieza
	 */
	public void agregarPieza(Pieza pieza) {
		this.getPedidoStrategy().addPieza(pieza);
	}
	
	/**
	 * Delego en el Strategy la responsabilidad de agregar piezas segun sea posible.
	 * @param pieza
	 */
	public void borrarPieza(Pieza pieza) {
		this.getPedidoStrategy().borrarPieza(pieza);
	}

	/**
	 * Pregunta al Strategy si el pedido posee una pieza dada
	 * @param pieza
	 * @return
	 */
	public Boolean tienePieza(Pieza pieza) {
		return this.getPiezas().contains(pieza);
	}

	public PedidoStrategy getPedidoStrategy() {
		return this.pedidoStrategy;
	}

	public void setPedidoStrategy(PedidoStrategy pedidoState) {
		this.pedidoStrategy = pedidoState;
	}

	/**
	 * Cuando un pedido se vende/efectiviza, se crea la venta asociada al mismo
	 * y las piezas pasan a estar en estado 'efectivo'
	 */
	public void efectivizar() {
		this.setPedidoStrategy(new PedidoEfectivoStrategy(this.getPiezas()));
	}

	/**
	 * Cuando un pedido se cancela, la piezas vuelven a estar disponibles
	 */
	public void cancelar() {
		this.setPedidoStrategy(new PedidoCanceladoStrategy(this.getPiezas()));
	}

	/**
	 * Al crearse un nuevo pedido, automaticamente se crea una reserva asociada
	 * al mismo, y las piezas pasan a estar en estado 'en curso'
	 * @param piezas 
	 */
	public void reservar(List<Pieza> piezas) {
		this.setPedidoStrategy(new PedidoEnCursoStrategy(piezas));
	}

	/**
	 * Pide al Strategy las piezas y devuelve la cantidad
	 * @return
	 */
	public Integer getCantidadPiezas() {
		return this.getPiezas().size();
	}

	/**
	 * Borra el objeto de la base de datos
	 */
	@Override
	public void delete() {
		BaseDaoImpl<Pedido> dao = PedidoDao.getInstance();
		dao.delete(this);
	}

	/**
	 * Graba el objeto en la base de datos. 
	 * Si no hay una session abierta, la abre.
	 */
	@Override
	public void save() {
		BaseDaoImpl<Pedido> dao = PedidoDao.getInstance();
		dao.save(this);
	}

	/**
	 * @return Si el pedido esta cancelado
	 */
	public boolean estaCancelado() {
		return this.getPedidoStrategy().estaCancelado();
	}

	/**
	 * @return Si el pedido esta en curso
	 */
	public boolean estaEnCurso() {
		return this.getPedidoStrategy().estaEnCurso();
	}

	/**
	 * @return Si el pedido esta efectivizado
	 */
	public boolean estaEfectivizado() {
		return this.getPedidoStrategy().estaEfectivizado();
	}
	
	/**
	 * @return El precio con 2 decimales para mostrar por pantalla
	 */
	public Float getPrecioParseado(){
		float precio = 0f; 
		for (Pieza pieza : this.getPiezas()) {
			precio += pieza.getPrecioSegunMoneda();
		}
		return Utils.parseFloatTo2DecimalesHalfUp(precio);
	}

	public void remove(BaseEntity entity) {
		// TODO Auto-generated method stub
		
	}
	
	//metodo usado por jsf
	public Boolean getNoEstaCancelado(){
		return !this.estaCancelado();
	}
	
	//metodo usado por jsf
	public Boolean getEstaEnCurso(){
		return this.getNoEstaCancelado() && !this.estaEfectivizado();
	}
}
